import numpy as np
from factor_analyzer import FactorAnalyzer
from scipy.stats import bartlett
from factor_analyzer.factor_analyzer import calculate_kmo
import pandas as pd
from datetime import datetime
import os, sys


def generate_data(num_samples, num_variables):
    # 生成随机数据（示例）
    data = np.random.rand(num_samples, num_variables)
    return data

def validate_data(data):
    # 执行探索性因子分析（EFA）

    """ 这段代码执行EFA的作用是计算数据集中的因子结构,并估计因子载荷和相关性等信息。

    EFA的主要目的是找到数据集中的潜在因子结构,这对于数据降维、特征选择和理解数据之间的关系非常有用。因子分析可以帮助您理解数据中的潜在结构,识别主要因子,以及选择最重要的特征。但需要注意,EFA通常用于探索性数据分析,而不是修改原始数据。

    执行EFA后,原始数据 data 不会改变,但您可以访问 EFA 模型 fa 来获取有关数据的因子分析结果,如因子载荷、因子方差解释等。 """

    fa = FactorAnalyzer(rotation=None)  # 不进行因子旋转
    fa.fit(data)

    # 计算KMO值
    kmo = calculate_kmo(data)

    """  KMO(Kaiser-Meyer-Olkin)值是一个元组(静态数组),包括两个值,其中第一个值是一个数组,包含每个变量的部分KMO值,而第二个值是总体KMO值。在这个上下文中,我们关心的是总体KMO值,因为它表示整个数据集的适合度,用于判断是否适合进行因子分析。

    因此,我们从KMO计算结果的元组中提取第二个元素,即总体KMO值,以便将其与0.7到0.9之间的范围进行比较,来判断数据集是否适合进行探索性因子分析。其他的部分KMO值通常用于更详细的分析,例如了解每个变量对因子分析的贡献。

    我之前的回答中混淆了KMO值的表示方式,因此需要从元组中提取第二个元素以获得总体KMO值。再次感谢您的耐心,希望这次的解释更加清楚。 """

    kmo_value = kmo[1]  # 提取KMO值


    # 进行Bartlett球形检验
    # _, bartlett_p_value: 这一行代码同时为Bartlett检验的结果分配了两个变量。_通常用作一个占位符,表示我们不关心的值,而bartlett_p_value用来存储Bartlett检验的p值。
    # *号代表 将变量中可迭代对象的元素拆解出来，作为独立的参数第传给函数

    # _, bartlett_p_value = bartlett(*data.T)
    _, bartlett_p_value = bartlett(*data)

    # data.T 是 data 的转置。转置操作将数组的行和列互换。这是因为在 Bartlett 球形检验中，要求输入的数据应该是以变量为列、观察样本为行的格式。因此，通过使用 data.T，您将数据的结构调整为正确的格式。
    # 这行代码生成的数据已经是 "变量为列、观察样本为行" 的格式了，不需要额外的转换。


    # 输出KMO值和Bartlett检验的结果
    print("KMO值:", kmo_value)
    validation_txt = None
    # 判断是否通过效度检验
    if 0.7 <= kmo_value <= 0.9 and bartlett_p_value < 0.05:
        validation_txt = "通过效度检验"
    else:
        validation_txt = "未通过效度检验"

    print(validation_txt)

    return kmo_value, bartlett_p_value, validation_txt



def save_to_excel(data,validation_result, dest_dir):

     # 获取当前日期时间作为前缀
    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")

    # 构建完整的文件名
    dest = os.path.join(dest_dir, f"{timestamp}_data_with_validation.xlsx")

    # 将数据转换为DataFrame
    df = pd.DataFrame(data)

    # 创建保存目录（如果不存在）
    os.makedirs(os.path.dirname(dest), exist_ok=True)

    # 将DataFrame保存为Excel文件
    df.to_excel(dest, index=False)

    
    # 创建包含验证结果的DataFrame
    validation_df = pd.DataFrame({
        'KMO值': [validation_result[0]],
        'Bartlett球形检验的p值': [validation_result[1]],
        '效度验证结果': [validation_result[2]]
    })

     # 将验证结果添加到Excel文件中
    with pd.ExcelWriter(dest, engine='openpyxl', mode='a', if_sheet_exists='replace') as writer:
        validation_df.to_excel(writer, sheet_name='Validation', index=False)

    print(f"数据已保存到 {dest}")

# 调用函数并生成数据
# generate_and_validate_data(num_samples=100, num_variables=10)

def generate_valigate_save_excel(num_sample_para,num_variabel_para):
    data = generate_data(num_samples=num_sample_para, num_variables=num_variabel_para)
    # 调用效度检验函数
    validation_result = validate_data(data)
    # 调用保存到Excel文件的函数
    save_to_excel(data, validation_result,'dest') 

